# 函数就是封装一组代码（后续反复调用无需重复写里面的代码块）
# 如下面的代码，我想执行五遍，并且想在我让他执行的位置执行
# 最笨的方法
"""
result = input("今年天气怎么样？")
# 在这下面，我想执行一次
print("小兔子乖乖")
print("把门儿开开")
print("快点儿开开")
print("我要进来")
result1 = input("今天吃什么？")
# 在这下面，我想执行一次
print("小兔子乖乖")
print("把门儿开开")
print("快点儿开开")
print("我要进来")
result2 = input("今天去哪玩")
# 在这下面，我想执行一次
print("小兔子乖乖")
print("把门儿开开")
print("快点儿开开")
print("我要进来")
result3 = input("今天去干啥")
# 在这下面，我想执行一次
print("小兔子乖乖")
print("把门儿开开")
print("快点儿开开")
print("我要进来")
result4 = input("今天住哪里")
# 在这下面，我想执行一次
print("小兔子乖乖")
print("把门儿开开")
print("快点儿开开")
print("我要进来")
"""
# 优化，代码简洁。可以封装成函数，在需要它的时候，去调用
def test01():
    print("小兔子乖乖")
    print("把门儿开开")
    print("快点儿开开")
    print("我要进来")
"""
result = input("今年天气怎么样？")
test01()
result1 = input("今年吃什么？")
test01()
# len() # 内置函数
"""
"""
ss = "asd"
print(ss.endswith("d")) # True \ False
print(ss.title())
"""
# 第一种：无形参，无返回
def student_info():
    print("大家好，我叫做侯雯中")
    print("今年95岁")
    print("我来自沈阳市")


# student_info()
# 调用
# student_info()
# 啥是返回值？
# print(student_info()) #  None 你去print下函数调用的地方，返回为None，就说明没有返回值
# 第二种，无形参，有返回
def student_info1():
    # student_info()
    return "大家好，我叫侯雯中\n今年19岁"
# student_info1()
"""
# return：表示返回值，return后面代码不会继续执行了
# 单纯的如此调用，不会有任何的内容返回
student_info1()
# 你需要打印一下它的返回值
print(student_info1())
# 或者，你可以拿它的返回值，做你想做的事？
str1 = student_info1() # str1 是什么？ 就是字符串：大家好，我叫侯雯中\n今年19岁
print(str1 + "，来自辽宁省沈阳市")
"""
def student_info2():
    return "大家好，我叫侯雯中\n今年19岁"
    print("来自辽宁省沈阳市") # return后面的代码块，不会被执行。
"""
student_info2() # 如此调用，也不会执行78行代码
print(student_info2())
"""
# 第三种：有形参，无返回
def student_info3(cname:str):  # cname: str ,表示cname的参数必须是str类型
    # 形参不能以关键字命名：print、input、set、for、while、int、list、tuple、dict....
    if cname =="22期班级":
        print("22期班级正在学习python")
    elif cname=="21期班级":
        print("21期班级已经全部就业")
    elif cname == "20期班级":
        print("20期班级已经上班三个月了！")
    else:
        print("你输入的班级不存在啊")
# 定义好了形参，一定要传递，不然会报错
# student_info3() # TypeError: student_info3() missing 1 required positional argument: 'cname'
# student_info3(cname="22期班级")
# student_info3("23期班级")
# 有形参，无返回，案例二
"""
def student_info4(cname:str,address:str): # 两个形参
    if cname =="22期" and address =="旭辉中心B座3301":
        print("这个班级还在上课中")
    elif cname == "4期" and address == "沈北新区":
        print("这个班级不存在，已经搬到了新的地方")
    else:
        print("班级不存在，地方也不存在")
# 调用
student_info4(cname="22期",address="旭辉中心B座3301") # 指定参数传递
student_info4("4期","沈北新区") # 没有指定参数传递，默认是按照函数定义的顺序传参
"""
# 第四种：有形参，有返回
def student_info_6(cname):
    if cname == "22":
        return "22期正在学习python"
    elif cname=="23":
        return "23期班级还没有开班，预计是在4.1号"
    elif cname=="24":
        return "24期班级预计是在5.25号开班"
    else:
        return "班级不存在！"
# 调用
# print(student_info_6("22"))
# 函数案例：计算器
def Calculator(symbol:str,a:int,b:int): # symbol、a、b都是形参，形式参数
    if symbol == "+":
        print(f"{a} + {b} 的结果为：{a+b}")
        return a+b
    elif symbol == "-":
        print(f"{a} - {b} 的结果为：{a - b}")
        return a - b
    elif symbol =="*":
        print(f"{a} * {b} 的结果为：{a * b}")
        return a * b
    elif symbol == "//":
        print(f"{a} ÷ {b} 的结果为：{a // b}")
        return a // b
    elif symbol == "/":
        print(f"{a} ÷ {b} 的结果为：{a / b}")
        return a / b
    else:
        print("输入错误！")
        return "输入错误！"
# "+"  10  20  : 这种参数都叫做实参，实际参数传递
# Calculator("+", 10, 20)
# 函数内部调用另外一个函数
def execute1():
    print("execute1开始执行了")
    execute2()
    print("execute2执行结束了")
def execute2():
    print("execute2开始执行了")
    print("execute2执行结束了")
# execute1()
"""
执行顺序
execute1：
execute1开始执行了
execute2开始执行了
execute2执行结束了
execute2执行结束了
"""
a = 100  # 全局变量
word = "hello" # 全局变量
x = "go"
def text():
    x = "hello" # 局部变量
    print("x = {}".format(x))
    a = 10 # 局部变量
    print("函数内部a = {}".format(a))
# 变量查找的优先级：优先用方法本身的变量，本身没有才会向上去找
# text()
"""
x = hello
函数内部a = 10
"""
def text1():
    print("x = {}".format(x)) # 内部函数没有被定义的时候，就会向上找全局变量
    print("函数内部a = {}".format(a)) # 内部函数没有被定义的时候，就会向上找全局变量
# text1()
"""
执行结果：
x = go
函数内部a = 100
"""
# 在函数内，我想改变全局变量的值？
def text2():
    x = 'og'
    word = 'baibai'
    a = '001'
    print(f"x = {x}")
    print(f"word = {word}")
    print(f"a = {a}")
# text2()
"""
x = og
word = baibai
a = 001
"""
# 全局变量并没有真的改掉，刚才函数用的是它本身的局部变量
"""
print(x) # go
print(word) # hello
print(a) # 100
"""
def text3():
    global x,word,a # 修改全局变量的值。一定要先声明，再改内容
    x = 'og'
    word = 'baibai'
    a = '001'
    print(f"x = {x}")
    print(f"word = {word}")
    print(f"a = {a}")
# text3()
"""
x = og
word = baibai
a = 001
"""
# 这个时候就是真的改掉了，因为text3不讲道理，用了global，所以全局变量都真的改掉了
# print(x)
# print(word)
# print(a)
"""
og
baibai
001
"""
def text4():
    x = 'hello1'
    a = 10
    print('locals = {},globals = {}'.format(locals(),globals()))
"""
locals():查看全部局部变量
globals():查看全部全局变量
"""
# text4()
# nonlocal：引用父函数的变量

def func2():
    b = 100 # b变量归属于func2
    def func3():
        nonlocal b # 如果想要改变func2里的b变量，就需要声明一下
        b += 1 # 100+1？101
        print(b) # 101
    # 函数没有带括号，就不算调用，返回的是一个地址值
    return func3()
# 闭包
def func1():
    b = 100 # b变量归属于func2
    def func3():
        nonlocal b # 如果想要改变func2里的b变量，就需要声明一下
        b += 1 # 100+1？101
        print(b) # 101
    # 函数没有带括号，就不算调用，返回的是一个地址值
    return func3
"""
bb = func1() # 地址值
bb() # 101
bb() # 102
bb() # 103

cc = func1()
cc() # ? 101 为什么又变成101了呢？ 刚才不是103吗？
"""
"""
闭包：
1、最少两个函数能做出来
2、父函数要套一个子函数
3、子函数要引用父函数的变量，将值存住并修改
4、父函数return返回的是子函数的地址值
调用：
子函数需要带上括号，表示调用子函数的方法

"""

# 不定长参数
def func4(*agrs): # * agrs 表示不定长参数的接收，理论上来说没有限制
    print(agrs)
# 传参的类型不受限制，也没有长度要求
# func4(1,2,3,"侯雯中",[10,20,30],(10,20,30),{"姓名":"侯雯中"},{10,20,30},1.1)

# 不定长参数和正常的参数一起存在呢？
def func5(name,*agrs): # 正常的参数一定要定义在不定长参数的前面
    print(name,agrs)
    # print()
# func5("侯雯中",1,2,3,{1,2,3})
"""
name = "侯雯中
agrs = (1,2,3,{1,2,3})
"""
# 不定长参数和正常的参数一起存在，我不听劝，我就把不定长放到前面，就硬整
def func6(*agrs,name):
    print(agrs)
    print(name)
#
# func6(1,2,3,{10,20,30},"侯雯中")

# 需要指定位置传参
# func6(1,2,3,{10,20,30},name="侯雯中")

# 不定长关键字传参
def func7(**kwagrs):
    print(kwagrs)

# 不定长字典传参
# func7(姓名="侯雯中",年龄="19",性别="女")
# 返回的内容是一个字典：{'姓名': '侯雯中', '年龄': '19', '性别': '女'}
"""
不定长参数有哪些？
*agrs：不定长参数传递，可以传任意类型。这种返回的是元组
**kwagrs：不定长关键字传参，只能传入字典形式。这种返回的是字典
"""
# 默认参数传递
def func8(name="侯雯中",age=19):
    print(f"大家好，我叫做{name}，今年{age}岁")
# 默认参数：当我没有传递参数的时候，它是一个默认值的状态
func8()
# 默认参数值改变
func8(name="金巴",age=23)
func8("金巴plus",age=99)